<?php
/**
 * Class rail_sequenceIterator
 *
 * An iterator over elements from an rail_sequence object.
 *
 **
 * rail_iterator
 *   |
 *   + rail_sequenceIterator
 *
 * PHP versions 5
 * See http://www.open-rail.org for more informations.
 *
 **
 * Copyright (C)
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of ERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software
 * Fundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 *
 **
 * @author Bastian Che Schröder <bastian@open-rail.org>
 * @version 2009-09-11
 * @package rail
 */
class rail_sequenceIterator implements rail_iterator {

	/**
	 * The rail_sequence object.
	 *
	 * @var rail_sequence
	 */
	private $rail_sequence;

	/**
	 * The current selected element in this sequence
	 *
	 * @var array
	 */
	private $element = array( 'index'=>null, 'object'=>null, 'previous'=>null, 'next'=>null );

	/**
	 * The first index in sequence for this iterator object.
	 *
	 * @var int
	 */
	private $first_index = null;


	/**
	 * Constructor for rail_iterator objects require a rail_sequence object, optional a Index to start.
	 *
	 * @exception rail_param_exception|rail_writepermission_exception
	 * @param rail_sequence $pRailSequence
	 * @param int $pIndex (optional)
	 */
	public function __construct( $pRailSequence, $pIndex = null ){
		// check read permission
		if( !$pRailSequence->is_readable() )
		 	throw new rail_readpermission_exception( $pRailSequence, $pRailSequence->rail_connector->get_user() );
		// check object type of pRailSequence
		if( !$pRailSequence instanceof rail_sequence )
		 	throw new rail_param_exception( null, '$pRailSequence', get_class($pRailSequence) );
		// check whether pIndex is a part of this sequence
		if( $pIndex != null ){
			$data = $this->rail_connector->send_request( "SELECT * FROM " . $pRailSequence->mysql_table_prefix . "objects_sequences WHERE `sequence`='" . $this->rail_sequence->get_id() . "' AND `id`='$pIndex' LIMIT 1" );
			$element = $data->fetch_assoc();
			if( count( $element ) <= 0 )
				throw new rail_exception( null, "rail_sequenceIteratot: The index $pIndex is not a part of this sequence.");
		}

		$this->rail_sequence = $pRailSequence;
		$this->first_index = $pIndex;
	}


	/**
	 * Add a new rail_object to sequence, direct before the next element.
	 *
	 * @param rail_object $pRailObject
	 */
	public function add ( $pRailObject ) {
		// call function from rail_sequence object
		$this->rail_sequence->insert_element( $this->element[ 'index' ], $pRailObject );
	}


	/**
	 * Check whether an next element exists. Return true if an element exist otherwise false.
	 *
	 * @return boolean
	 */
	public function has_next () {
		// if no element is selected
		if( $this->element['index'] == null ){
			if( $this->first_index == null )
				$data = $this->rail_connector->send_request( "SELECT * FROM " . $this->rail_sequence->mysql_table_prefix . "objects_sequences WHERE `sequence`='" . $this->rail_sequence->get_id() . "' AND `previous`='0' LIMIT 1" );
			else $data = $this->rail_connector->send_request( "SELECT * FROM " . $this->rail_sequence->mysql_table_prefix . "objects_sequences WHERE `id`='" . $this->first_index . "' AND LIMIT 1" );

			// fetch element
			$element = $pData->fetch_assoc();
			return count( $element ) > 0;
				return true;
		}

		// an element is selected
		return $this->element[ 'next' ] != 0;
	}


	/**
	 * Check whether an previous element exists. Return true if an element exist otherwise false.
	 *
	 * @return boolean
	 */
	public function has_previous () {
		// if no element is selected
		if( $this->element['index'] == null )
			return false;

		// true if current element has a previous id
		return $this->element[ 'previous' ] != 0;
	}


	/**
	 * Return the index of the current element in sequence. Throw an exception if no element is selected.
	 *
	 * @exception rail_exception
	 * @return int
	 */
	public function index () {
		if( $this->element['index'] == null )
			throw new rail_exception( $this->rail_sequence, 'rail_sequenceIteratot: no element selected.');

		return $this->element['index'];
	}


	/**
	 * Get the next element in this sequence. Throw an exception if next element dosn't exists.
	 *
	 * @exception rail_exception
	 * @return rail_object
	 */
	public function next () {
		// none element is selected
		if( $this->element['index'] == null && $this->first_index == null )
			$data = $this->rail_connector->send_request( "SELECT * FROM " . $this->rail_sequence->mysql_table_prefix . "objects_sequences WHERE `sequence`='" . $this->rail_sequence->get_id() . "' AND `previous`='0' LIMIT 1" );
		else if( $this->element['index'] == null )
			$data = $this->rail_connector->send_request( "SELECT * FROM " . $this->rail_sequence->mysql_table_prefix . "objects_sequences WHERE `id`='" . $this->first_index . "' AND LIMIT 1" );
		// an element is selected
		else if( $element[ 'next' ] != 0 )
			$data = $this->rail_connector->send_request( "SELECT * FROM " . $this->rail_sequence->mysql_table_prefix . "objects_sequences WHERE `id`='" . $this->element[ 'next' ] . "' LIMIT 1" );
		else
			throw new rail_exception( $this->rail_sequence, 'rail_sequenceIteratot: next element dosn\'t exists.');

		// fetch element
		$element = $pData->fetch_assoc();
		if( count( $element ) <= 0 )
			throw new rail_exception( $this->rail_sequence, 'rail_sequenceIteratot: next element missing.');

		$this->element = array(
			'index' => $element[ 'id' ],
		 	'object' => $element[ 'object' ],
		 	'previous' => $element[ 'previous' ],
		 	'next' => $element[ 'next' ],
		);

		// return object
		return rail_factory::get_object( $this->rail_sequence->get_rail_connector(), $this->element['object'] );
	}


	/**
	 * Return the index for the next element in sequence. Throw an exception if next index dosn't exists.
	 *
	 * @exception rail_exception
	 * @return int
	 */
	public function next_index () {
		// if no element is selected
		if( $this->element['index'] == null ){
			if( $this->first_index == null )
				$data = $this->rail_connector->send_request( "SELECT * FROM " . $this->rail_sequence->mysql_table_prefix . "objects_sequences WHERE `sequence`='" . $this->rail_sequence->get_id() . "' AND `previous`='0' LIMIT 1" );
			else $data = $this->rail_connector->send_request( "SELECT * FROM " . $this->rail_sequence->mysql_table_prefix . "objects_sequences WHERE `id`='" . $this->first_index . "' AND LIMIT 1" );

			// fetch element
			$element = $pData->fetch_assoc();
			if( count( $element ) > 0 )
				return $element[ 'id' ];
			else
				throw new rail_exception( $this->rail_sequence, 'rail_sequenceIteratot: the sequence is empty.');
		}

		// an element is selected
		if( $this->element[ 'next' ] == 0 )
			throw new rail_exception( $this->rail_sequence, 'rail_sequenceIteratot: next element dosn\'t exists.');

		return $this->element[ 'next' ];
	}


	/**
	 * Get the previous element in this sequence. Throw an exception if previous element dosn't exists.
	 *
	 * @exception rail_exception
	 * @return rail_object
	 */
	public function previous () {
		// if no element is selected or previous element dosn't exists
		if( $this->element['index'] == null || $this->element['previous'] == 0 )
			throw new rail_exception( $this->rail_sequence, 'rail_sequenceIteratot: no previous element exists.');

		// get previous element's recordset from mysql
		$data = $this->rail_connector->send_request( "SELECT * FROM " . $this->rail_sequence->mysql_table_prefix . "objects_sequences WHERE `id`='" . $this->element[ 'previous' ] . "' LIMIT 1" );

		// fetch element and check wheater mysql result is empty
		$element = $pData->fetch_assoc();
		if( count( $element ) <= 0 )
			throw new rail_exception( $this->rail_sequence, 'rail_sequenceIteratot: previous element missing.');

		$this->element = array(
			'index' => $element[ 'id' ],
		 	'object' => $element[ 'object' ],
		 	'previous' => $element[ 'previous' ],
		 	'next' => $element[ 'next' ],
		);

		// return object
		return rail_factory::get_object( $this->rail_sequence->get_rail_connector(), $this->element['object'] );
	}


	/**
	 * Return the index for the previous element in sequence. Throw an exception if no previous index exists.
	 *
	 * @exception rail_exception
	 * @return int
	 */
	public function previous_index () {
		// check whether previous index exists
		if( $this->element['index'] == null || $this->element[ 'previous' ] == 0 )
			throw new rail_exception( $this->rail_sequence, 'rail_sequenceIteratot: no previous index exists.');

		// return previous index
		return $this->element[ 'previous' ];
	}


	/**
	 * Remove the current selected element in sequence. Means the last element returned by next or previous
	 * methods. Throw an exception if no element is selected.
	 *
	 * @exception rail_exception
	 */
	public function remove () {
		// check whether an element is selected
		if( $this->element[ 'index' ] == null )
			throw new rail_exception( $this->rail_sequence, 'rail_sequenceIteratot: no element is selected.');

		// call function from rail_sequence object
		$this->rail_sequence->remove_element( $pIndex );
	}

} // End of rail_sequenceIterator
?>